package com.lancer.platform.pay.rest.param;

import com.lancer.platform.pay.utils.ListUtils;
import com.lancer.platform.pay.utils.ListUtilsHook;
import com.lancer.platform.pay.utils.ListUtilsHookUp;
import org.glassfish.jersey.uri.UriComponent;

import javax.ws.rs.client.WebTarget;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public class QueryParam {

    private final ConcurrentMap<String, List<String>> queryParams;

    private QueryParam() {
        this.queryParams = new ConcurrentHashMap<>();
    }

    public static QueryParam build() {
        return new QueryParam();
    }

    public QueryParam append(String queryParamName, Object... queryParams) {
        Objects.requireNonNull(queryParamName, "QueryParamName is null.");
        Objects.requireNonNull(queryParams, "QueryParams are null.");
//        List<String> toAppendValues = Stream.of(queryParams).filter(p -> p != null).map(Object::toString).collect(Collectors.toList());
        List<String> toAppendValues = ListUtils.filterAndToString(Arrays.asList(queryParams), new ListUtilsHook<Object>() {
            @Override
            public boolean test(Object str) {
                return str != null;
            }
        });
        List<String> queryParamValues = this.queryParams.putIfAbsent(queryParamName, toAppendValues);
        if (queryParamValues != null) {
            queryParamValues.addAll(toAppendValues);
        }

        return this;
    }

    public <T> QueryParam append(String queryParamName, List<T> queryParams) {
        Objects.requireNonNull(queryParamName, "QueryParamName is null.");
        Objects.requireNonNull(queryParams, "QueryParams are null.");
//        List<String> toAppendValues = queryParams.stream().filter(p -> p != null).map(Object::toString).collect(Collectors.toList());
        List<String> toAppendValues = ListUtils.filterAndToString(queryParams, new ListUtilsHook<T>() {
            @Override
            public boolean test(T str) {
                return str != null;
            }
        });
        List<String> queryParamValues = this.queryParams.putIfAbsent(queryParamName, toAppendValues);
        if (queryParamValues != null) {
            queryParamValues.addAll(toAppendValues);
        }

        return this;
    }

    public WebTarget appendToTarget(WebTarget target) {
        WebTarget newTarget = target;
        for (String queryParamName : this.queryParams.keySet()) {
            List<String> queryParamValues = this.queryParams.get(queryParamName);
            for (String queryParamValue : queryParamValues) {
                newTarget = newTarget.queryParam(queryParamName,
                        UriComponent.encode(queryParamValue, UriComponent.Type.QUERY_PARAM_SPACE_ENCODED));
            }
        }

        return newTarget;
    }

    @Override
    public String toString() {

//        return this.queryParams.entrySet().stream().filter(e -> e.getKey() != null && e.getValue() != null)
//                .map(e -> e.getValue().stream().filter(v -> v != null)
//                  .map(v -> e.getKey() + "=" + v).collect(Collectors.joining("&")))
//                .collect(Collectors.joining("&", "{QueryParam: ", "}"));


        List<String> strList = new ArrayList<>();
        for (final Map.Entry<String, List<String>> entry : this.queryParams.entrySet()) {
            if (entry.getKey() == null || entry.getValue() == null) {
                continue;
            }
            List<String> r = ListUtils.filter(entry.getValue(), new ListUtilsHookUp<String>() {
                String key = entry.getKey();
                @Override
                public boolean test(String s) {
                    return s != null;
                }

                @Override
                public String doing(String v) {
                    return  key + "=" + v;
                }

            });
            strList.add(ListUtils.joining(r, "&"));
        }
        return ListUtils.joining(strList, "&", "{QueryParam:","}");
    }

}
